package com.garbagecode.routetable.path;

import java.util.List;
import java.util.Map;

import com.garbagecode.routetable.Route;

/**
 * 
 * 这个 Path 的实现不允许路径间冲突
 * 比如：
 * "/hello/world" 与 "/hello/:who" 冲突
 * "/hello/:who" 与 "/hello/:name" 冲突
 * "/hello/:who" 与 "/hi/:who" 不冲突
 */
public class StrictPath extends PathImpl {

  public StrictPath() {
    super();
  }

  public StrictPath(char[] array, Map<Character, Path> nextPathMap, List<Route> routeList) {
    super(array, nextPathMap, routeList);
  }

  public StrictPath(char[] array) {
    super(array);
  }

  @Override
  public void add(char[] array, int offset, Route route) {
    if (array == null) {
      throw new IllegalArgumentException("array null");
    }

    if (route == null) {
      throw new IllegalArgumentException("route null");
    }

    if (offset >= array.length) {
      throw new IllegalArgumentException("offset out of bounds");
    }
    
    // 匹配已有的路由
    Route findResult = find(route.getPath().toCharArray(), offset, false);
    
    // 若匹配到已有的路由则代表这要添加的路径与已有的路径冲突
    if (findResult != null) {
      String messageFormat = "path '%s' confilct with path '%s'";
      String errorMessage = String.format(messageFormat, route.getPath(), findResult.getPath());
      throw new RuntimeException(errorMessage);
    }

    super.add(array, offset, route);
  }

  /**
   * 返回参数 array 和 offset 匹配到的路由
   * @param array
   * @param offset
   * @param fuzzyMatch
   * @return
   */
  protected Route find(char[] array, int offset, boolean fuzzyMatch) {
    if (array == null) {
      throw new IllegalArgumentException("array null");
    }

    if (offset >= array.length) {
      throw new IllegalArgumentException("offset out of bounds");
    }

    char[] array1 = getArray();
    char[] array2 = array;
    int index1 = 0;
    int index2 = offset;
    char ch1;
    char ch2;

    if (fuzzyMatch) {
      while (index1 < array1.length) {
        if (array1[index1] == '/') {
          fuzzyMatch = false;
          break;
        }

        index1 = index1 + 1;
      }
    }

    while (index1 < array1.length && index2 < array2.length) {
      ch1 = array1[index1];
      ch2 = array2[index2];

      if (ch2 == ':') {
        fuzzyMatch = true;

        while (index2 < array2.length && array2[index2] != '/') {
          index2 = index2 + 1;
        }

        while (index1 < array1.length) {
          if (array1[index1] == '/') {
            fuzzyMatch = false;
            break;
          }

          index1 = index1 + 1;
        }
      } else if (ch1 == ch2) {
        index1 = index1 + 1;
        index2 = index2 + 1;
        continue;
      } else if (ch1 != ch2) {
        break;
      }
    }

    if (index1 < array1.length) {
      return null;
    }
    
    StrictPath path = null;
    Route route = getRoute(getRouteList(), array2, index2);
    
    if (route != null) {
      return route;
    }

    for (Map.Entry<Character, Path> entry : getNextPathMap().entrySet()) {
      path = (StrictPath) entry.getValue();
      route = path.find(array2, index2, fuzzyMatch);

      if (route != null) {
        break;
      }
    }

    return route;
  }

  @Override
  protected PathImpl createPath() {
    return new StrictPath();
  }

}
